﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Linq;
using UtilZ.Dotnet.Ex.Base;
using UtilZ.Dotnet.Ex.Log;
using UtilZ.Dotnet.Ex.ParaManagement;

namespace ConAppCore.Test
{
    internal class TestParaManager
    {
        public static void Test()
        {
            //Test1();
            //Test2();
            Test3();
            //Test4();
        }

        private static void Test4()
        {
            ParaManager paraManager = new ParaManager();
            string paraName = "freq";

            long? freq = null;
            paraManager.Set(paraName, freq);

            long? freq2 = paraManager.GetParaValue<long?>(paraName);
        }

        private static void Test3()
        {
            var paraConverter = new TestParaConverter();

            ParaManager para = new ParaManager();
            para.Converter = paraConverter;

            para.Set("enum", TestConvertEx.ConvertExEnum.M);
            para.Set("str", "yf张");
            para.Set("valueType", 123);
            para.Set("refObj", new StuInfo() { Age = 21, Id = 2, Name = "yy" });
            para.Set("list", new List<StuInfo> { new StuInfo() { Age = 22, Id = 11, Name = "qq" }, new StuInfo() { Age = 22, Id = 22, Name = "yy" } });
            para.Set("list2", new List<ChannelUnit>
            {
                new ChannelUnit() { MchNum = 1, Freq = 101, Mod = 1, BW = 100, SEL = 1, SaveCtrl = 1 },
                new ChannelUnit() { MchNum = 2, Freq = 202, Mod = 2, BW = 200, SEL = 2, SaveCtrl = 2 }
            });

            para.Set("arr", new StuInfo[] { new StuInfo() { Age = 22, Id = 11, Name = "qq" }, new StuInfo() { Age = 22, Id = 22, Name = "yy" } });
            para.Set("cusObj", new StuInfo() { Age = 25, Id = 50, Name = "ccc" });
            para.Save("testPara.xml");

            ParaManager para2 = new ParaManager();
            para2.Converter = paraConverter;
            para2.Load("testPara.xml");

            var refObj = para2.GetParaValue<StuInfo>("refObj");
            var list = para2.GetParaValue<List<StuInfo>>("list");
            var list2 = para2.GetParaValue<List<ChannelUnit>>("list2");
            var arr = para2.GetParaValue<StuInfo[]>("arr");
        }


        private static ConcurrentDictionary<string, object> _dic = null;
        private static AutoResetEvent _autoReset = null;
        private static AutoResetEvent _autoReset2 = null;
        private static int _index = 0;
        private static void Test2()
        {
            try
            {
                _dic = new ConcurrentDictionary<string, object>();
                _dic.Add("aa", "111");
                _dic.Add("bb", 222);
                _dic.Add("cc", 3333);
                _dic.Add("dd", 444);
                _dic.Add("ee", "555");
                _dic.Add("ff", 666);

                object value = 456;
                object ret = _dic.AddOrUpdate("dd", value, (key, oldValue) =>
                {
                    return value;
                });

                _autoReset = new AutoResetEvent(false);
                _autoReset2 = new AutoResetEvent(false);
                Task.Factory.StartNew(() =>
                {
                    string key;
                    while (_dic.Count > 0)
                    {
                        _autoReset.WaitOne();
                        key = _dic.Keys.ElementAt(_index);
                        if (_dic.TryRemove(key, out var tmpValue))
                        {
                            Console.WriteLine($"{Thread.CurrentThread.ManagedThreadId}  remove:{key} ok");
                        }
                        else
                        {
                            Console.WriteLine($"{Thread.CurrentThread.ManagedThreadId}  remove:{key} fail");
                        }
                        _autoReset2.Set();
                    }
                });

                StringBuilder sb = new StringBuilder();
                bool flag = false;
                foreach (var kv in _dic)
                {
                    Console.WriteLine($"{Thread.CurrentThread.ManagedThreadId}  keys:{string.Join(',', _dic.Keys)}");
                    sb.AppendLine($"{kv.Key}    {kv.Value}");
                    flag = !flag;

                    if (flag)
                    {
                        _index += 2;
                        _autoReset.Set();
                        _autoReset2.WaitOne();
                    }
                }
                Console.WriteLine($"{Thread.CurrentThread.ManagedThreadId}  {sb.ToString()}");
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
        }


        private static void Test1()
        {
            string paraName1 = "enum1";
            string paraName2 = "enum2";
            string paraName3 = "str";
            string paraName4 = "num";
            string filePath = PathEx.GetFullPath("para.xml");

            ParaManager para = new ParaManager();
            //para.Load(filePath);
            para.OnParaChanged += (s, e) =>
            {
                if (e.AddParas != null)
                {
                    Console.WriteLine($"增加参数:{string.Join(',', e.AddParas)}");
                }

                if (e.UpgradeParas != null)
                {
                    Console.WriteLine($"更新参数:{string.Join(',', e.UpgradeParas)}");
                }

                if (e.RemoveParas != null)
                {
                    Console.WriteLine($"移除参数:{string.Join(',', e.RemoveParas)}");
                }
            };
            Loger.Info($"设备\"{filePath}\"工作参数加载完成...");
            para.Set(paraName1, WeekEnum.Friday);
            para.Set(paraName2, TestConvertEx.ConvertExEnum.M);
            para.Set(paraName3, "张小abc");
            para.Set(paraName4, 125);
            para.Save(filePath);

            para.Set("yf", 25);
            para.Set(paraName4, 23);
            para.Set(paraName4, 23);
            para.Set(paraName4, 25);
            para.Remove(paraName4);
            para.Set(paraName4, 25);

            var para2 = new ParaManager();
            para2.Load(filePath);
            para2.Resolving += (s, e) =>
            {
                switch (e.ParaName)
                {
                    case "extenPara":
                        e.Value = "25";
                        e.Succes = true;
                        break;
                    default:
                        break;
                }
            };
            var v1 = para2.GetParaValue<WeekEnum>(paraName1);
            var v2 = para2.GetParaValue<TestConvertEx.ConvertExEnum>(paraName2);
            var v3 = para2.GetParaValue<string>(paraName3);
            var v4 = para2.GetParaValue<int>(paraName1);
            var v5 = para2.GetParaValue<int>("extenPara");
            if (para2.TryGetParaValue<int>("extenPara2", out int v6))
            {
                Console.WriteLine($"获取扩展参数2成功:{v6}");
            }
            else
            {
                Console.WriteLine("获取扩展参数2失败");
            }



            string paraName = "name";
            para.Set(paraName, 18);
            int age = para.GetParaValue<int>(paraName);
            Console.WriteLine($"age:{age}");
        }

    }


    internal class TestParaConverter : IParaConverter
    {
        public TestParaConverter()
        {

        }

        /// <summary>
        /// 尝试将内存参数值转写到XElement中[写入成功返回true,失败返回false]
        /// </summary>
        /// <param name="paraItemEle">参数项元素</param>
        /// <param name="paraName">参数名称</param>
        /// <param name="value">参数值对象</param>
        /// <returns>写入成功返回true,失败返回false</returns>
        public bool TryWriteTo(XElement paraItemEle, string paraName, object value)
        {
            if (string.Equals("cusObj", paraName, StringComparison.Ordinal))
            {
                var stuInfo = (StuInfo)value;
                string valueStr = $"{stuInfo.Id}|{stuInfo.Age}|{stuInfo.Name}";
                paraItemEle.Add(new XCData(valueStr));
                return true;
            }
            else
            {
                return false;
            }
        }

        /// <summary>
        /// 尝试从XElement中中读取内存参数值[读取成功返回true,失败返回false]
        /// </summary>
        /// <param name="paraItemEle">参数项元素</param>
        /// <param name="paraName">参数名称</param>
        /// <param name="value">结果参数值对象</param>
        /// <returns>读取成功返回true,失败返回false</returns>
        public bool TryReadFrom(XElement paraItemEle, string paraName, out object value)
        {
            if (string.Equals("cusObj", paraName, StringComparison.Ordinal))
            {
                string[] strs = paraItemEle.Value.Split('|');
                value = new StuInfo() { Id = int.Parse(strs[0]), Age = int.Parse(strs[1]), Name = strs[2] };
                return true;
            }
            else
            {
                value = null;
                return false;
            }
        }
    }


    public class ChannelUnit
    {
        public byte? MchNum { get; set; }
        public long? Freq { get; set; }
        public byte? Mod { get; set; }
        public Int32? BW { get; set; }
        public byte? SEL { get; set; }
        public byte? SaveCtrl { get; set; }

    }
}
